/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */
package info.peigen.hotpot.common.service.base;


import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import info.peigen.hotpot.common.core.result.ListResult;
import info.peigen.hotpot.common.core.result.SingleResult;
import info.peigen.hotpot.common.service.base.event.LogEventHandler;
import info.peigen.hotpot.common.service.base.event.ServiceOrderLogEvent;
import info.peigen.hotpot.common.service.base.event.ServiceResultLogEvent;
import info.peigen.hotpot.common.service.base.gateway.GatewayFacade;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContext;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContextThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <b>(AbstractDomainService)</b>
 * 领域服务层基类,建议继承
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2019/05/19
 */
@SuppressWarnings("resource")
@Slf4j
public abstract class AbstractDomainService<M, T> implements DomainService {

    @Inject
    protected LogEventHandler logEventHandler;
    @Inject
    protected ProfileConfig   profileConfig;
    @Inject
    protected AppContext      context;

    public void execute(ServiceContext serviceContext, DomainServiceInvoke invoke) {

        // 0. 打印[开始]日志
        StopWatch watch = serviceContext.getWatch();
        watch.start("入参打印");
        ServiceOrderBase     order    = serviceContext.getOrder();
        ServiceOrderLogEvent logEvent = ServiceOrderLogEvent.builder().order(order).build();
        logEventHandler.eventPost(logEvent);
        watch.stop();
        try {
            // 1. 校验入参
            watch.start("入参校验");
            invoke.checkOrder(serviceContext);
            watch.stop();

            // 2. 激活领域对象
            watch.start("激活领域对象");
            invoke.activeDomain(serviceContext);
            watch.stop();

            // 3. 服务调用
            if (profileConfig.isMock()) {
                watch.start("Mock封装");
                if (ObjectUtil.isNull(ServiceTestMockContextThreadLocal.currentContext())) {
                    new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().build());
                }

                // 3.1 Mock Gateway Service Facade
                if (ObjectUtil.isNotNull(serviceContext.getGatewayFacade())) {
                    List<GatewayFacade> beans       = context.getBeansOfType(GatewayFacade.class);
                    String              serviceName = serviceContext.getGatewayFacade().getClass().getSimpleName();
                    beans.stream().filter(bean -> StrUtil.equals(bean.getClass().getSimpleName(), "Mock"))
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(serviceName))
                            .findAny().ifPresent(serviceContext::setGatewayFacade);
                }
                // 3.2 Mock Other Service Facade
                if (ObjectUtil.isNotNull(serviceContext.getServiceFacade())) {
                    List<ServiceFacade> serviceFacadeBeans = context.getBeansOfType(ServiceFacade.class);
                    String serviceFacadeName = serviceContext.getServiceFacade().getClass()
                            .getSimpleName();
                    serviceFacadeBeans.stream().filter(bean -> StrUtil.equals(bean.getClass().getSimpleName(), "Mock"))
                            .filter(bean -> bean.getClass().getSimpleName().replaceAll("Mock", "")
                                    .equalsIgnoreCase(serviceFacadeName))
                            .findAny().ifPresent(serviceContext::setServiceFacade);
                }
                watch.stop();
            }
            watch.start("服务封装");
            invoke.invoke(serviceContext);
            watch.stop();

            // 5. 发送异步[数据存储]事件
            watch.start("发送异步[数据存储]事件");
            invoke.handleStoreDataEvent(serviceContext);
            watch.stop();

            // 5. 打印[结果]日志
            watch.start("打印[结果]日志");
            ServiceResultLogEvent resultLogEvent = ServiceResultLogEvent.builder()
                    .productCode(order.getProductCode())
                    .bizOrderNo(order.getBizOrderNo())
                    .build();

            if (serviceContext.getResult() instanceof ListResult) {
                resultLogEvent.setListResult((ListResult<?>) serviceContext.getResult());
            }

            if (serviceContext.getResult() instanceof SingleResult) {
                resultLogEvent.setSingleResult((SingleResult<?>) serviceContext.getResult());
            }

            logEventHandler.eventPost(resultLogEvent);
            watch.stop();

            log.debug(watch.prettyPrint(TimeUnit.SECONDS));
        } catch (Exception e) {
            invoke.handleException(e, serviceContext);
        }

    }

}